﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.IO;
using System.Xml;
using System.Xml.Linq;

namespace STEditor.Classes.Tests
{
    [TestClass]
    public class STGameXamlWriter_GameDataTests
    {

        private const string TilesFolder = @"C:\Users\Rune\Documents\Visual Studio 2010\Projects\SilverTileApp\Assets";

        private DirectoryInfo _folder = null;
        private XDocument _gameData = null;

        [TestInitialize]
        public void Initialize()
        {
            _folder = new DirectoryInfo(Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()));

            string tileName1 = "ZeldaTiles-0001-(0-0).png";
            string tileName2 = "ZeldaTiles-0002-(1-0).png";

            var saveGame = new STGame();
            var tile1 = saveGame.TileTypes.Add(Path.Combine(TilesFolder, tileName1));
            var tile2 = saveGame.TileTypes.Add(Path.Combine(TilesFolder, tileName2));

            var gameArea = new STGameArea { TileWidth = 32, TileHeight = 20, Width = 3, Height = 1, AreaName = "Area1" };
            gameArea.SetTile(0, 0, tile1).Blocking = true;
            gameArea.SetTile(1, 0, tile2).Blocking = false;
            gameArea.SetTile(2, 0, tile2).Blocking = false;
            saveGame.GameAreas.Add(gameArea);

            new STGameXamlWriter().Save(saveGame, _folder.FullName);

            var gameDataFile = new FileInfo(Path.Combine(_folder.FullName, STGameXamlWriter.GameDataFileName));
            
            using (var gameDataStream = gameDataFile.OpenRead())
            {
                _gameData = XDocument.Load(gameDataStream);
            }

        }

        [TestCleanup]
        public void CleanUp()
        {
            if (_folder.Exists)
            {
                _folder.Delete(true);
            }
        }

        [TestMethod]
        public void Writer_Save_Should_Generate_The_Expected_RootNode_In_GameData_File()
        {
                
            XElement rootNode = _gameData.FirstNode as XElement;
            Assert.AreEqual("ResourceDictionary", rootNode.Name.LocalName, "Root element is not a ResourceDictionary");
        }

        [TestMethod]
        public void Writer_Save_Should_Create_SpriteFrame_Nodes_For_Each_Tile_Used()
        {

            XElement rootNode = _gameData.FirstNode as XElement;
            var spriteFrames = rootNode.DescendantsAndSelf().Where(e => e.Name.LocalName.Equals("SpriteFrame"));
            Assert.AreEqual(2, spriteFrames.Count(), "Did not find 2 SpriteFrame elements");

            var frame1 = spriteFrames.First();
            var frame2 = spriteFrames.Skip(1).First();
            string expectedSource1 = string.Format("/SilverTileApp;component/{0}/{1}", STGameXamlWriter.TilesFolderName, "ZeldaTiles-0001-(0-0).png");
            string expectedSource2 = string.Format("/SilverTileApp;component/{0}/{1}", STGameXamlWriter.TilesFolderName, "ZeldaTiles-0002-(1-0).png");

            Assert.AreEqual("ZeldaTiles-0001-(0-0)", GetAttribute(frame1, "Key"), "Key was not set correcly for frame1");
            Assert.AreEqual(expectedSource1, GetAttribute(frame1, "Source"), "Source was not set correctly for frame1");

            Assert.AreEqual("ZeldaTiles-0002-(1-0)", GetAttribute(frame2, "Key"), "Key was not set correcly for frame2");
            Assert.AreEqual(expectedSource2, GetAttribute(frame2, "Source"), "Source was not set correctly for frame2");

        }

        [TestMethod]
        public void Writer_Save_Should_Create_GameAreaGrid_Element_With_Expected_Attributes()
        {

            var rootNode = _gameData.FirstNode as XElement;
            var gridElement = _gameData.Descendants().Where(e => e.Name.LocalName.Equals("GameAreaGrid")).Single();

            Assert.IsNotNull(gridElement);
            
            var keyAttribute = GetAttribute(gridElement, "Key"); //.Attributes().Where(a => a.Name.LocalName.Equals("Key")).Single();
            Assert.AreEqual("Area1", keyAttribute, "Key was not stored correctly");

            var areaNameAttribute = GetAttribute(gridElement, "AreaName"); // gridElement.Attributes().Where(a => a.Name.LocalName.Equals("AreaName")).Single();
            Assert.AreEqual("Area1", areaNameAttribute, "AreaName was not stored correctly");

            var columnsAttribute = GetAttribute(gridElement, "Columns");
            Assert.AreEqual("3", columnsAttribute, "Columns was not set correctly");

            var rowsAttribute = GetAttribute(gridElement, "Rows");
            Assert.AreEqual("1", rowsAttribute, "Rows was not set correctly");

            var tileWidthAttribute = GetAttribute(gridElement, "TileWidth");
            Assert.AreEqual("32", tileWidthAttribute, "TileWidth was not set correctly");

            var tileHeightAttribute = GetAttribute(gridElement, "TileHeight");
            Assert.AreEqual("20", tileHeightAttribute, "TileHeight was not set correctly");

        }

        [TestMethod]
        public void Writer_Save_Should_Create_Elements_For_Each_Tile_In_A_Game_Area()
        {

            var rootNode = _gameData.FirstNode as XElement;
            var gridElement = _gameData.Descendants().Where(e => e.Name.LocalName.Equals("GameAreaGrid")).Single();

            var spriteTiles = gridElement.Descendants().Where(e => e.Name.LocalName.Equals("SpriteTile"));

            Assert.AreEqual(3, spriteTiles.Count(), "Incorrect number of tiles written");

            var tile1 = spriteTiles.First();
            var tile2 = spriteTiles.Skip(1).First();

            Assert.AreEqual("0", GetAttribute(tile1, "X"), "X for tile 1 was not set correctly");
            Assert.AreEqual("0", GetAttribute(tile1, "Y"), "Y for tile 1 was not set correctly");
            Assert.AreEqual("True", GetAttribute(tile1, "Blocking"), "Blocking for tile 1 was not set correctly");
            Assert.AreEqual("{StaticResource ZeldaTiles-0001-(0-0)}", GetAttribute(tile1, "Frame"), "Frame for tile 1 was not set correctly");

            Assert.AreEqual("1", GetAttribute(tile2, "X"), "X for tile 1 was not set correctly");
            Assert.AreEqual("0", GetAttribute(tile2, "Y"), "Y for tile 1 was not set correctly");
            Assert.AreEqual("False", GetAttribute(tile2, "Blocking"), "Blocking for tile 1 was not set correctly");
            Assert.AreEqual("{StaticResource ZeldaTiles-0002-(1-0)}", GetAttribute(tile2, "Frame"), "Frame for tile 2 was not set correctly");


        }

        private string GetAttribute(XElement element, string attributeName)
        {
            var attribute = element.Attributes().Where(a => a.Name.LocalName.Equals(attributeName)).FirstOrDefault();

            if (attribute == null)
            {
                return string.Empty;
            }
            return attribute.Value;
        }

    }
}
